package com.kaguya.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 结构型 动态代理 - jdk，接口代理，需要被代理对象实现接口
 * Proxy:代理类，newProxyInstance()方法返回一个Object类型的代理对象，可强制类型转换为指定的代理对象类型，
 * 入参：被代理对象的ClassLoader,被代理对象的接口，invocationHandler对象
 *
 * InvocationHandler接口，只有一个invoke方法，实现该方法，可配合反射去调用被代理对象的方法，
 * 并可在方法调用前后去自定义实现，这个方法返回代理之后的对象。
 * invoke(Object proxy,Method method,Object[] args) 调用这个方法的代理实例，被代理对象的方法对象，被代理对象的方法入参
 * 原理：1.通过Proxy的newProxyInstance方法创建了一个代理对象。
 *      2.实现了InvocationHandler并实现了invoke方法，
 *      3.后续调用方法时实际上是invoke返回的对象
 * -------------------------------------------------------------------------------------------------------
 *
 * cglib代理：
 * 1.cglib代理也叫做子类代理，他在内存中创建一个子类对象，从而实现对目标对象的扩展
 * 2.cglib是一个高性能的代码生成包，可以在运行期间扩展java类与实现java接口，被广泛用于AOP的框架
 * 3.底层是通过字节码处理框架ASM来转换字节码并生成新的类
 * 4.较于jdk动态代理，无需 被代理对象实现接口。
 */
public class DynamicProxy {
    public static void main(String[] args) {
        Entry entryInstance = new EntryProxy().getInstance(new MyEntry());
        entryInstance.doSomeThing();;
    }
}

interface Entry {
    void doSomeThing();
}
/**
 * 实体类 被代理类
 */
class MyEntry implements Entry{
    @Override
    public void doSomeThing() {
        System.out.println("hello我今天很愉快");
    }
}

/**
 * 代理类
 */
class EntryProxy implements InvocationHandler {

    private MyEntry myEntry;

    public Entry getInstance(MyEntry myEntry){
        this.myEntry = myEntry;
        return (Entry) Proxy.newProxyInstance(myEntry.getClass().getClassLoader(),myEntry.getClass().getInterfaces(),this);
    }

    /**
     * invoke实现
     * @param proxy 调用这个方法的代理实例
     * @param method 原对象方法
     * @param args 原对象方法入参
     * @return 实现代理之后的对象
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        // 利用反射，根据方法名调用invoke方法，并对其进行增强
        if(method.getName().equalsIgnoreCase("dosomething")) {
            System.out.println("执行dosomething");
            result = method.invoke(myEntry,args);
        }
        return result;
    }
}
